﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenTK.Graphics.OpenGL;
using OpenTK;

namespace SoilProfiler
{
    public partial class frm3Dview : Form
    {
        bool loaded = false;
        ConfigurareTriangulation _data;
        Columns _columns;
        int[] list;
        Camera camera;

        bool info = false;

        public Dictionary<string, Color> Colors { get; set; }
        float latitude;
        float longitude;
        float twist;
        float latinc;
        float longinc;
        float GLOBAL_radius;
        double xmin;
        double xmax;
        double ymin;
        double ymax;
        double zmin;
        double zmax;


        public frm3Dview()
        {
            InitializeComponent();
        }

        int options = 2;

        bool viewTransect = false;
        public frm3Dview(ConfigurareTriangulation data, Columns columns, Dictionary<string, Color> col, DrawProfile _Draw)
        {
            this._data=data;
            this._columns = columns;
            this.Colors = col;
            this._Draw = _Draw;

            if (_Draw != null )
            {
                if (_Draw.Information != null)
                    Transect = _Draw.Information;
            
            }

            if(data!= null && columns!=null)
               info = true;


            InitializeComponent();
        }


        public frm3Dview(ConfigurareTriangulation data, Columns columns)
        {
            this._data = data;
            this._columns = columns;

            if (data != null && columns != null)
                info = true;


            InitializeComponent();
        }


        Dictionary<string, int> layers = new Dictionary<string, int>();

        private void glControl1_Load(object sender, EventArgs e)
        {
            loaded = true;

            if (!info)
                return;

            foreach (string item in Colors.Keys.ToArray())
            {
                uxLayerList.Items.Add(item);
            }

           // uxLayerList.Items.Add("All");


            camera = new Camera();
            GL.ShadeModel(ShadingModel.Smooth);
            GL.Enable(EnableCap.DepthTest);
            GL.DepthMask(true);
            GL.DepthFunc(DepthFunction.Less);
            GL.ClearColor(Color.White);


            CalculateMaximum(out xmin, out xmax, out ymin, out ymax, out zmin, out zmax);




            list = new int[Colors.Keys.Count+3];

            for (int i = 0; i < Colors.Keys.Count; i++)
            {
                list[i] = GL.GenLists(Colors.Keys.Count + 3);
                LoadVertex(ref list[i], Colors.Keys.ToArray()[i]);
                
                layers.Add(Colors.Keys.ToArray()[i], list[i]);
            }


            ConfigureCamera(xmin, xmax, ymin, ymax, zmin, zmax);



            list[Colors.Keys.Count+1] = GL.GenLists(Colors.Keys.Count + 3);
            CreateOrigin(ref list[Colors.Keys.Count+1], xmin, xmax, ymin, ymax, zmin, zmax);
            
            layers.Add("Axes", list[Colors.Keys.Count+1]);

            if (Transect != null)
            {

                uxViewTransect.Enabled = true;

                list[Colors.Keys.Count + 2] = GL.GenLists(Colors.Keys.Count + 3);
                CreateTransect(ref list[Colors.Keys.Count + 2]);
             


            }




            camera.OnResize(Width, Height);

        }

        private void CreateTransect(ref int p)
        {
            GL.NewList(p, ListMode.Compile);
            {
                GL.Begin(BeginMode.Points);
                foreach (DataPRofile item in Transect)
                {
                    GL.Color3(Colors[item.type]);
                    GL.Vertex3(item.x, item.y, item.value);

                }
                GL.EndList();
            }
            GL.EndList();

        }

        private void Cube()
        {
       




            GL.Begin(BeginMode.Quads);
          
            GL.Vertex3(-1.0f, -1.0f, -1.0f);	// Top Right Of The Texture and Quad
            GL.Vertex3(1.0f, -1.0f, -1.0f);	// Top Left Of The Texture and Quad
            GL.Vertex3(1.0f, -1.0f, 1.0f);	// Bottom Left Of The Texture and Quad
            GL.Vertex3(-1.0f, -1.0f, 1.0f);	// Bottom Right Of The Texture and Quad
             //Front Face
            GL.Vertex3(-1.0f, -1.0f, 1.0f);	// Bottom Left Of The Texture and Quad
            GL.Vertex3(1.0f, -1.0f, 1.0f);	// Bottom Right Of The Texture and Quad
            GL.Vertex3(1.0f, 1.0f, 1.0f);	// Top Right Of The Texture and Quad
            GL.Vertex3(-1.0f, 1.0f, 1.0f);	// Top Left Of The Texture and Quad
            // Back Face
            GL.Vertex3(-1.0f, -1.0f, -1.0f);	// Bottom Right Of The Texture and Quad
            GL.Vertex3(-1.0f, 1.0f, -1.0f);	// Top Right Of The Texture and Quad
            GL.Vertex3(1.0f, 1.0f, -1.0f);	// Top Left Of The Texture and Quad
            GL.Vertex3(1.0f, -1.0f, -1.0f);	// Bottom Left Of The Texture and Quad
            // Right face
            GL.Vertex3(1.0f, -1.0f, -1.0f);	// Bottom Right Of The Texture and Quad
            GL.Vertex3(1.0f, 1.0f, -1.0f);	// Top Right Of The Texture and Quad
            GL.Vertex3(1.0f, 1.0f, 1.0f);	// Top Left Of The Texture and Quad
            GL.Vertex3(1.0f, -1.0f, 1.0f);	// Bottom Left Of The Texture and Quad
            // Left Face
            GL.Vertex3(-1.0f, -1.0f, -1.0f);	// Bottom Left Of The Texture and Quad
            GL.Vertex3(-1.0f, -1.0f, 1.0f);	// Bottom Right Of The Texture and Quad
            GL.Vertex3(-1.0f, 1.0f, 1.0f);	// Top Right Of The Texture and Quad
            GL.Vertex3(-1.0f, 1.0f, -1.0f);	// Top Left Of The Texture and Quad
            GL.End();
        
        
        }
        private void ConfigureCamera(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax)
        {

            camera = new Camera((float)((xmax + xmin) / 2), (float)(ymax + ymin) / 2, (float)((zmax + zmin) / 2));



            uxLat.Maximum = Convert.ToInt32(ymax + 100000);
            uxLat.Minimum = Convert.ToInt32(ymin - 100000);
            uxLon.Maximum = Convert.ToInt32(xmax + 100000);
            uxLon.Minimum = Convert.ToInt32(xmin - 100000);
            uxRadius.Maximum = Convert.ToInt32(zmax + 150000);
            uxRadius.Minimum = Convert.ToInt32(zmin - 1000);
            uxLat.SmallChange = 100;
            uxLon.SmallChange = 100;
            uxRadius.SmallChange = 100;

          
            uxLat.Value = (int)(((ymax + ymin) / 2)) + 100000;
            uxLon.Value = (int)(xmax + 100000);
            uxRadius.Value = (int)(zmax + 150000);
            uxYCenter.Text = uxLat.Value.ToString();
            uxXCenter.Text = uxLon.Value.ToString();
            uxZCenter.Text = uxRadius.Value.ToString();
            camera.Move((float)(xmax + 100000), (float)(((ymax + ymin) / 2) + 100000), (float)(zmax + 150000));
            latitude = uxLat.Value;
            longitude = uxLon.Value;
            GLOBAL_radius = uxRadius.Value;


        }


        private void LoadVertex(ref int list)
        {
            

            GL.NewList(list, ListMode.Compile);
            {
                GL.Begin(BeginMode.Triangles);

                foreach (Volume item in _data.VolumeInfo)
                {
                    foreach (var item2 in item.Layers)
                    {
                        Vector3 one = new Vector3(
                           (float)item2.vertex[0].X,
                            (float)item2.vertex[0].Y,
                             (float)item2.vertex[0].Z
                                  );
                    
                        Vector3 two = new Vector3(
                           (float)item2.vertex[1].X,
                            (float)item2.vertex[1].Y,
                             (float)item2.vertex[1].Z
                                  );

                        Vector3 three = new Vector3(
                        (float)item2.vertex[2].X,
                         (float)item2.vertex[2].Y,
                          (float)item2.vertex[2].Z
                               );


                        GL.Color3(Colors[item2.Hguname]);
                        GL.Vertex3(one);
                        GL.Vertex3(two);
                        GL.Vertex3(three);
                    }


                }
                GL.End();

            }
        }


        private void LoadVertex(ref int list, string unit)
        {


            GL.NewList(list, ListMode.Compile);
            {
                GL.Begin(BeginMode.Triangles);

                foreach (Volume item in _data.VolumeInfo)
                {
                    foreach (var item2 in item.Layers)
                    {
                        if (item2.Hguname == unit)
                        {

                            Vector3 one = new Vector3(
                               (float)item2.vertex[0].X,
                                (float)item2.vertex[0].Y,
                                 (float)item2.vertex[0].Z
                                      );

                            Vector3 two = new Vector3(
                               (float)item2.vertex[1].X,
                                (float)item2.vertex[1].Y,
                                 (float)item2.vertex[1].Z
                                      );

                            Vector3 three = new Vector3(
                            (float)item2.vertex[2].X,
                             (float)item2.vertex[2].Y,
                              (float)item2.vertex[2].Z
                                   );


                            GL.Color3(Colors[item2.Hguname]);
                            GL.Vertex3(one);
                            GL.Vertex3(two);
                            GL.Vertex3(three);
                        }
                    }


                }
                GL.End();

            }
            GL.EndList();
        }



        private void CalculateMaximum( out double xmin, out double xmax, out double ymin, out double ymax, out double zmin, out double zmax)
        {
            
            List<double> valueX = new List<double>();
            List<double> valueZ = new List<double>();
            List<double> valueY = new List<double>();
            foreach (Volume item in _data.VolumeInfo)
            {
                foreach (var item2 in item.Layers)
                {
                    valueX.Add(item2.vertex[0].X);
                    valueY.Add(item2.vertex[0].Y);
                    valueZ.Add(item2.vertex[0].Z);
                    valueX.Add(item2.vertex[1].X);
                    valueY.Add(item2.vertex[1].Y);
                    valueZ.Add(item2.vertex[1].Z);
                    valueX.Add(item2.vertex[2].X);
                    valueY.Add(item2.vertex[2].Y);
                    valueZ.Add(item2.vertex[2].Z);
                }
            }
            xmin = valueX.Min();
            xmax = valueX.Max();
            ymin = valueY.Min();
            ymax = valueY.Max();
            zmin = valueZ.Min();
            zmax = valueZ.Max();
        }

        private void CreateOrigin(ref int list,double xmin, double xmax, double ymin, double ymax, double zmin, double zmax)
        {
          
            GL.NewList(list, ListMode.Compile);
            {
                GL.Begin(BeginMode.Lines);
                    Vector3 l1 = new Vector3((float)xmin, (float)ymin, (float)zmin);
                    Vector3 l2 = new Vector3((float)xmax + 100000, (float)ymin, (float)zmin);
                    Vector3 l3 = new Vector3((float)xmin, (float)ymax + 100000, (float)zmin);
                    Vector3 l4 = new Vector3((float)xmin, (float)ymin, (float)zmax + 100000);

                    GL.Vertex3(l1);
                    GL.Vertex3(l2);
                    GL.Vertex3(l1);
                    GL.Vertex3(l3);
                    GL.Vertex3(l1);
                    GL.Vertex3(l4);
                GL.End();

            }
            GL.EndList();

        }



        void PolarView(float radius, float twist,
                            float latitude, float longitude)
                {
            
                    GL.Translate(0.0, 0.0, -radius);
                    GL.Rotate(-twist, 0.0, 0.0, 1.0);
                    GL.Rotate(-latitude, 1.0, 0.0, 0.0);
                    GL.Rotate(longitude, 0.0, 0.0, 1.0);

                }


        private void glControl1_Resize(object sender, EventArgs e)
        {
            if (!loaded)
                return;
            if (!info)
                return;

            camera.OnResize(Width, Height);
        }

        int[] displayList = new int[0] { };


        private void glControl1_Paint(object sender, PaintEventArgs e)
        {
            if (!loaded)
                return;
            if (!info)
                return;
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            camera.Update();
            GL.Color3(0.0, 1.0, 1.0);

            latitude += latinc;
            longitude += longinc;
            twist += longinc;
          

            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
          


            if(edges==1)
                GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
            else
                GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);


            foreach (int item in displayList)
            {
                GL.CallList(item);
            }
         
           



            if (options == 2)
            {
                GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);

                foreach (LayerColumn item in _columns.Profiles)
                {
                    GL.Color3(Colors[item.Unit]);
                    GL.PushMatrix();
                    float d = (float)((item.bottom) + ((item.topelev - item.bottom) / 2));
                    float p = (float)(item.topelev - item.bottom);
                    GL.Translate((float)item.x, (float)item.y, (float)((item.bottom)+((item.topelev - item.bottom)/2)));
                    GL.Scale(50, 50, (float)(item.topelev - item.bottom));
                    GL.Scale(0.5, 0.5, 0.5);
                    Cube();
                    GL.PopMatrix();

                }

                GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);

                foreach (LayerColumn item in _columns.Profiles)
                {
                    GL.Color3(Color.Gray);
                    GL.PushMatrix();
                    float d = (float)((item.bottom) + ((item.topelev - item.bottom) / 2));
                    float p = (float)(item.topelev - item.bottom);
                    GL.Translate((float)item.x, (float)item.y, (float)((item.bottom) + ((item.topelev - item.bottom) / 2)));
                    GL.Scale(50, 50, (float)(item.topelev - item.bottom));
                    GL.Scale(1, 1, 0.5);
                    Cube();
                    GL.PopMatrix();

                }


            }




            GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
            GL.Color3(Color.Gray);
            GL.Begin(BeginMode.Lines);
            GL.CallList(list[Colors.Keys.Count + 1]);
            GL.End();

         
            //if (viewTransect)
            //{
            //    GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Point);
            //    GL.CallList(list[Colors.Keys.Count + 2]);
            //}
       



            glControl1.SwapBuffers();
        }

        private void uxApply_Click(object sender, EventArgs e)
        {

            displayList = new int[uxLayerList.SelectedItems.Count];
            int i=0;
            foreach (var v in uxLayerList.SelectedItems)
            {
                displayList[i] = layers[(string)v];
              i++;
            }
            glControl1.Refresh();
        }

        private void uxLat_Scroll(object sender, EventArgs e)
        {
           latitude = uxLat.Value;
           uxYCenter.Text = uxLat.Value.ToString();
           camera.Move(longitude, latitude, GLOBAL_radius);
           glControl1.Refresh();
        }

        private void uxLon_Scroll(object sender, EventArgs e)
        {
            longitude = uxLon.Value;
            uxXCenter.Text = uxLon.Value.ToString();
            camera.Move(longitude, latitude, GLOBAL_radius);
            glControl1.Refresh();
        }

        private void uxTwist_Scroll(object sender, EventArgs e)
        {
            twist = uxTwist.Value;
            glControl1.Refresh();
        
        }

        private void uxRadius_Scroll(object sender, EventArgs e)
        {
            GLOBAL_radius = uxRadius.Value;
            uxZCenter.Text = uxRadius.Value.ToString();
            camera.Move(longitude, latitude, GLOBAL_radius);
            glControl1.Refresh();
        }





        private void uxViewTriangulation_CheckedChanged(object sender, EventArgs e)
        {
            options = 1;
            glControl1.Refresh();
        }

        private void uxViewProfiles_CheckedChanged(object sender, EventArgs e)
        {
            options = 2;
            glControl1.Refresh();

        }

        private void uxViewTransect_CheckedChanged(object sender, EventArgs e)
        {
            if (uxViewTransect.Checked)
                 viewTransect = true;
            else
                 viewTransect = false;

            glControl1.Refresh();
        }

        private void uxLayerList_SelectedIndexChanged(object sender, EventArgs e)
        {
           
        }
        int edges = 0;
        private ConfigurareTriangulation TrianglesLayers;
        private Columns ProfileColumns;
        private Dictionary<string, Color> color;
        private DrawProfile _Draw;
        private void uxEdges_CheckedChanged(object sender, EventArgs e)
        {
            if (uxEdges.Checked)
                edges = 1;
            else
                edges = 0;
        }

        public List<DataPRofile> Transect { get; set; }
    }




}
